package com.lm.upms.service.impl;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lm.common.core.constant.CommonConstants;
import com.lm.common.core.util.R;
import com.lm.common.security.util.SecurityUtils;
import com.lm.upms.api.dto.UserDTO;
import com.lm.upms.api.dto.UserInfo;
import com.lm.upms.api.entity.SysDept;
import com.lm.upms.api.entity.SysRole;
import com.lm.upms.api.entity.SysUser;
import com.lm.upms.api.entity.SysUserRole;
import com.lm.upms.api.vo.MenuVO;
import com.lm.upms.api.vo.UserVO;
import com.lm.upms.mapper.SysUserMapper;
import com.lm.upms.service.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 用户
 *
 * @author lm
 * @date
 */
@Slf4j
@Service
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements SysUserService {

    @Autowired
    private SysRoleService sysRoleService;

    @Autowired
    private SysMenuService sysMenuService;

    @Autowired
    private SysDeptService sysDeptService;

    @Autowired
    private SysUserRoleService sysUserRoleService;

    //@Autowired
    //private SysDeptRelationService sysDeptRelationService;

    private static final PasswordEncoder ENCODER = new BCryptPasswordEncoder();

    @Override
    public SysUser findByUsername(String username) {
        return baseMapper.findByUsername(username);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean saveUser(UserDTO userDto) {
        SysUser sysUser = new SysUser();
        BeanUtils.copyProperties(userDto, sysUser);
        sysUser.setDelFlag(CommonConstants.STATUS_NORMAL);
        // TODO：全局配置生成默认密码
        sysUser.setPassword(ENCODER.encode("123456"));
        // sysUser.setPassword(ENCODER.encode(userDto.getPassword()));
        sysUser.setCreateBy(SecurityUtils.getUser().getUsername());
        baseMapper.insert(sysUser);
        List<SysUserRole> userRoleList = userDto.getRoleIds()
                .stream().map(roleId -> {
                    SysUserRole userRole = new SysUserRole();
                    userRole.setUserId(sysUser.getUserId());
                    userRole.setRoleId(roleId);
                    return userRole;
                }).collect(Collectors.toList());
        return sysUserRoleService.saveBatch(userRoleList);
    }

    @Override
    public UserInfo findUserInfo(SysUser sysUser) {
        UserInfo userInfo = new UserInfo();
        userInfo.setSysUser(sysUser);
        //设置角色列表（ID）
        List<Integer> roleIds = sysRoleService.findRolesByUserId(sysUser.getUserId())
                .stream()
                .map(SysRole::getRoleId)
                .collect(Collectors.toList());
        userInfo.setRoles(ArrayUtil.toArray(roleIds, Integer.class));

        // 设置权限列表（menu.permission）
        Set<String> permissions = new HashSet<>();
        roleIds.forEach(roleId -> {
            List<String> permissionList = sysMenuService.findMenuByRoleId(roleId)
                    .stream()
                    .filter(menuVo -> StringUtils.isNotEmpty(menuVo.getPerms()))
                    .map(MenuVO::getPerms)
                    .collect(Collectors.toList());
            permissions.addAll(permissionList);
        });
        userInfo.setPermissions(ArrayUtil.toArray(permissions, String.class));
        return userInfo;
    }

    @Override
    public IPage getUsersWithRolePage(Page page, UserDTO userDTO) {
        return baseMapper.getUserVosPage(page, userDTO);
    }

    @Override
    public UserVO selectUserVoById(Integer id) {
        return baseMapper.getUserVoById(id);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public R deleteUserById(String ids) throws Exception {
        Integer[] userIds = Convert.toIntArray(ids);
        for (Integer userId : userIds) {
            // 不能删除超级用户, 需要优化
            if (userId != null && 1L == userId) {
                throw new Exception("不允许删除超级管理员用户");
                //log.warn("不允许删除超级管理员用户");
                //return R.error("不允许删除超级管理员用户!");
            }
            sysUserRoleService.deleteByUserId(userId);
            this.removeById(userId);
            baseMapper.deleteById(userId);
        }
        return R.success("删除用户成功!");
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public R updateUserInfo(UserDTO userDto) {
        UserVO userVO = baseMapper.getUserVoByUsername(userDto.getUsername());
        SysUser sysUser = new SysUser();
        if (StrUtil.isNotBlank(userDto.getPassword())
                && StrUtil.isNotBlank(userDto.getNewPwd())) {
            if (ENCODER.matches(userDto.getPassword(), userVO.getPassword())) {
                sysUser.setPassword(ENCODER.encode(userDto.getNewPwd()));
            } else {
                log.warn("原密码错误，修改密码失败:{}", userDto.getUsername());
                return R.error("原密码错误，修改失败!");
            }
        }
        sysUser.setPhoneNumber(userDto.getPhoneNumber());
        sysUser.setUserId(userVO.getUserId());
        sysUser.setAvatar(userDto.getAvatar());
        return R.success(this.updateById(sysUser));
    }

    @Override
    public Boolean updateUser(UserDTO userDto) {
        SysUser sysUser = new SysUser();
        BeanUtils.copyProperties(userDto, sysUser);

        if (StrUtil.isNotBlank(userDto.getPassword())) {
            sysUser.setPassword(ENCODER.encode(userDto.getPassword()));
        }
        this.updateById(sysUser);

        sysUserRoleService.remove(Wrappers.<SysUserRole>update().lambda().eq(SysUserRole::getUserId, userDto.getUserId()));
        userDto.getRoleIds().forEach(roleId -> {
            SysUserRole userRole = new SysUserRole();
            userRole.setUserId(sysUser.getUserId());
            userRole.setRoleId(roleId);
            sysUserRoleService.getBaseMapper().insert(userRole);
        });
        return Boolean.TRUE;
    }

    @Override
    public List<SysUser> listAncestorUsers(String username) {
        SysUser sysUser = this.getOne(Wrappers.<SysUser>query().lambda().eq(SysUser::getUsername, username));

        SysDept sysDept = sysDeptService.getById(sysUser.getDeptId());
        if (sysDept == null) {
            return null;
        }

        Integer parentId = sysDept.getParentId();
        return this.list(Wrappers.<SysUser>query().lambda().eq(SysUser::getDeptId, parentId));
    }

}
